<template>
    <div :class="showProgress == true ? 'loading' : ''">
        <!-- on-preview	点击文件列表中已上传的文件时的钩子 -->
        <!-- http-request	覆盖默认的上传行为，可以自定义上传的实现 -->
        <!-- limit	最大允许上传个数 -->
        <!-- before-upload	上传文件之前的钩子，参数为上传的文件，若返回 false 或者返回 Promise 且被 reject，则停止上传。 -->
        <!-- accept	接受上传的文件类型（thumbnail-mode 模式下此参数无效） -->
        <!-- multiple	是否支持多选文件 -->
        <!-- on-change	文件状态改变时的钩子，添加文件、上传成功和上传失败时都会被调用 -->
        <!-- on-remove	文件列表移除文件时的钩子 -->
        <!-- file-list	上传的文件列表, 例如: [{name: 'food.jpg', url: 'https://xxx.cdn.com/xxx.jpg'}] -->
        <!-- on-exceed	文件超出个数限制时的钩子 -->
        <!-- auto-upload	是否在选取文件后立即进行上传 -->
        <!-- action	必选参数，上传的地址  例如  action="https://jsonplaceholder.typicode.com/posts/"-->
        <el-upload multiple :auto-upload="true" :http-request="checkedFile" :before-remove="removeFile" :limit="10"
                   action="/tools/upload_chunk/" :disabled="showProgress">
            <el-button type="primary">点击上传文件</el-button>
<!--            <div class="el-upload__text">-->
<!--                将文件拖到此处，或-->
<!--                <em>点击上传</em>-->
<!--            </div>-->
        </el-upload>
        <!-- 正在上传的弹窗 -->
        <el-dialog title="正在上传" :visible.sync="showProgress" width="50%">
            <el-progress type="circle" :percentage="progress" class="progress" v-if="showProgress"></el-progress>
        </el-dialog>
        <!-- <el-progress type="circle" :percentage="progress" class="progress" v-if="showProgress"></el-progress> -->
    </div>
</template>
<script>
import axios from "axios";
import SparkMD5 from "spark-md5";
export default {
    data() {
        return {
            maxSize: 5 * 1024 * 1024 * 1024, // 上传最大文件限制  最小单位是b
            multiUploadSize: 100 * 1024 * 1024, // 大于这个大小的文件使用分块上传(后端可以支持断点续传)  100mb
            eachSize: 100 * 1024 * 1024, // 每块文件大小   100mb
            requestCancelQueue: [], // 请求方法队列（调用取消上传
            url: "",
            //上传进度
            progress: 0,
            showProgress: false,
            // 每上传一块的进度
            eachProgress: 0,
            // 总共有多少块。断点续传使用
            chunksKeep: 0,
            // 切割后的文件数组
            fileChunksKeep: [],
            // 这个文件，断点续传
            fileKeep: null,
            // 断点续传，文件md5
            fileMd5Keep: ""
        };
    },
    mounted() { },
    methods: {
        async checkedFile(options) {
            // console.log(options);
            const {
                maxSize,
                multiUploadSize,
                getSize,
                splitUpload,
                singleUpload
            } = this; // 解构赋值
            const { file, onProgress, onSuccess, onError } = options; // 解构赋值
            if (file.size > maxSize) {
                return this.$message({
                    message: `您选择的文件大于${getSize(maxSize)}`,
                    type: "error"
                });
            }
            this.fileKeep = file;
            const uploadFunc =
                file.size > multiUploadSize ? splitUpload : singleUpload; // 选择上传方式
            try {
                await uploadFunc(file, onProgress);
                onSuccess();
            } catch (e) {
                console.error(e);
                this.$message({
                    message: e.message,
                    type: "error"
                });
                this.showProgress = false;
                this.progress = 0;
                onError();
            }
            const prom = new Promise((resolve, reject) => { }); // 上传后返回一个promise
            prom.abort = () => { };
            return prom;
        },
        // 格式化文件大小显示文字
        getSize(size) {
            return size > 1024
                ? size / 1024 > 1024
                    ? size / (1024 * 1024) > 1024
                        ? (size / (1024 * 1024 * 1024)).toFixed(2) + "GB"
                        : (size / (1024 * 1024)).toFixed(2) + "MB"
                    : (size / 1024).toFixed(2) + "KB"
                : size.toFixed(2) + "B";
        },
        // 单文件直接上传
        async singleUpload(file, onProgress) {
            await this.postFile(
                { file, uid: file.uid, fileName: file.fileName, chunk: 0 },
                onProgress
            );
            // var spark = new SparkMD5.ArrayBuffer();
            // spark.append(file);
            // var md5 = spark.end();
            // console.log(md5);

            const reader = new FileReader();

            reader.readAsArrayBuffer(file);
            let hashMd5 = "";
            console.log(hashMd5);
            const that = this;
            function getHash(cb) {
                console.log("进入单个上传的getHash");
                reader.onload = function (e) {
                    console.log("进入单个上传的getHash的函数2");
                    console.log(hashMd5);
                    console.log(this);
                    // console.log(e)
                    const hash = SparkMD5.ArrayBuffer.hash(e.target.result);
                    // const hash = SparkMD5.ArrayBuffer.hash(file);
                    console.log(hash);
                    that.hashMd5 = hash;
                    console.log(that.hashMd5);
                    that.fileMd5Keep = hash;
                    cb(hash);
                };
            }
            await getHash(function (hash) {
                console.log(hash);
                console.log(that);
                // 请求接口
                that.validateFile({
                    name: file.name,
                    uid: file.uid,
                    md5: hash,
                    chunks: 1,
                    filter_type: "user_data_file"
                });
            });
        },
        // getMd5(file, chunkCount) {
        //   const spark = new SparkMD5.ArrayBuffer();
        //   let currentChunk = 0;

        //   const reader = new FileReader();

        //   reader.onload = function(e) {
        //     spark.append(e.target.result);
        //     currentChunk++;

        //     if (currentChunk < chunkCount) {
        //       console.log(currentChunk);
        //       loadNext();
        //     } else {
        //       console.log(spark.end());
        //       // 在这里请求接口
        //       return spark.end();
        //     }
        //   };

        //   function loadNext() {
        //     const start = currentChunk * chunkSize;
        //     const end =
        //       start + chunkSize >= file.size ? file.size : start + chunkSize;
        //     reader.readAsArrayBuffer(file.slice(start, end));
        //   }

        //   loadNext();
        // },
        // 大文件分块上传
        splitUpload(file, onProgress) {
            return new Promise(async (resolve, reject) => {
                try {
                    const { eachSize } = this;
                    const chunks = Math.ceil(file.size / eachSize);
                    this.chunksKeep = chunks;
                    const fileChunks = await this.splitFile(file, eachSize, chunks);
                    this.fileChunksKeep = fileChunks;
                    console.log("fileChunks,文件数组切割后");
                    console.log(fileChunks);
                    //判断每上传一个文件，进度条涨多少,保留两位小数
                    this.eachProgress = parseInt(Math.floor((100 / chunks) * 100) / 100);
                    this.showProgress = true;
                    let currentChunk = 0;

                    for (let i = 0; i < fileChunks.length; i++) {
                        // 服务端检测已经上传到第currentChunk块了，那就直接跳到第currentChunk块，实现断点续传
                        console.log(currentChunk, i);
                        // 此时需要判断进度条
                        if (Number(currentChunk) === i) {
                            // 每块上传完后则返回需要提交的下一块的index
                            await this.postFile(
                                {
                                    chunked: true,
                                    chunk: i,
                                    chunks,
                                    eachSize,
                                    fileName: file.name,
                                    fullSize: file.size,
                                    uid: file.uid,
                                    file: fileChunks[i]
                                },
                                onProgress
                            );
                            currentChunk++;

                            // 上传完一块后，进度条增加
                            this.progress += this.eachProgress;
                            // 不能超过100
                            this.progress = this.progress > 100 ? 100 : this.progress;
                        }
                    }
                    // this.getMd5(file, chunks);
                    // var spark = new SparkMD5.ArrayBuffer();
                    // spark.append(file);
                    // var md5 = spark.end();
                    // console.log(md5);
                    const spark = new SparkMD5.ArrayBuffer();
                    let currentChunkMd5 = 0;
                    const that = this;
                    const reader = new FileReader();
                    reader.onload = async function (e) {
                        spark.append(e.target.result);
                        currentChunkMd5++;

                        if (currentChunkMd5 < chunks) {
                            loadNext();
                        } else {
                            // console.log(spark.end());
                            var hashMd5111 = spark.end();
                            that.fileMd5Keep = hashMd5111;
                            console.log(that);
                            console.log(hashMd5111);
                            // 在这里请求接口
                            await that.validateFile({
                                name: file.name,
                                uid: file.uid,
                                md5: hashMd5111,
                                chunks: fileChunks.length,
                                filter_type: "git_secret_file"
                                // chunk: fileChunks.length,
                            });
                        }
                    };

                    async function loadNext() {
                        const start = currentChunkMd5 * eachSize;
                        const end =
                            start + eachSize >= file.size ? file.size : start + eachSize;
                        await reader.readAsArrayBuffer(file.slice(start, end));
                    }
                    this.$message({
                        message: "正在进行文件加密校验",
                        type: "info"
                    });
                    await loadNext();
                    // let hashMd5 = "";
                    // // console.log(hashMd5)
                    // const that = this;
                    // console.log("进入分片上传的getHash");
                    // function getHash(cb) {
                    //   reader.onload = function(e) {
                    //     console.log("进入分片上传的getHash的函数");
                    //     const hash = SparkMD5.ArrayBuffer.hash(e.target.result);
                    //     // const hash = SparkMD5.ArrayBuffer.hash(file);
                    //     console.log(hash);
                    //     that.hashMd5 = hash;
                    //     console.log(that.hashMd5);
                    //     that.fileMd5Keep = hash;
                    //     cb(hash);
                    //   };
                    //   reader.readAsArrayBuffer(file);
                    // }
                    // await getHash(function() {
                    //   console.log(that);
                    //   that.validateFile({
                    //     name: file.name,
                    //     uid: file.uid,
                    //     md5: that.hashMd5,
                    //     chunks: fileChunks.length
                    //     // chunk: fileChunks.length,
                    //   });
                    // });
                    // 请求接口

                    // console.log('fileChunks.length')
                    // 请求接口
                    // this.validateFile({
                    //   fileName: file.name,
                    //   uid: file.uid,
                    //   md5:md5,
                    //   chunks:1
                    // });
                    resolve();
                } catch (error) {
                    reject(error);
                }
            });
        },
        // 断点续传
        againSplitUpload(file, array) {
            console.log("file,array");
            console.log(file);
            console.log(array);
            return new Promise(async (resolve, reject) => {
                try {
                    const { eachSize, fileKeep } = this;
                    const chunks = this.chunksKeep;
                    const fileChunks = this.fileChunksKeep;
                    this.showProgress = true;
                    // let currentChunk = 0;
                    for (let i = 0; i < array.length; i++) {
                        // 服务端检测已经上传到第currentChunk块了，那就直接跳到第currentChunk块，实现断点续传
                        // console.log(currentChunk, i);
                        // 此时需要判断进度条
                        // 每块上传完后则返回需要提交的下一块的index
                        await this.postFile({
                            chunked: true,
                            chunk: array[i],
                            chunks,
                            name: file.name,
                            fullSize: fileKeep.size,
                            uid: file.uid,
                            file: fileChunks[array[i]]
                        });
                        // currentChunk++

                        // 上传完一块后，进度条增加
                        // this.progress += this.eachProgress;
                        // 不能超过100
                        this.progress = this.progress > 100 ? 100 : this.progress;
                    }
                    // var spark = new SparkMD5.ArrayBuffer();
                    // spark.append(fileKeep);
                    // var md5 = spark.end();
                    // console.log(md5);

                    var fileMd5KeepTwo = this.fileMd5Keep;

                    const isValidate = await this.validateFile({
                        chunks: fileChunks.length,
                        // chunk: fileChunks.length,
                        name: file.name,
                        uid: file.uid,
                        md5: fileMd5KeepTwo,
                        filter_type: "git_secret_file"
                        // task_id:file.uid
                    });
                    // if (!isValidate) {
                    //   throw new Error("文件校验异常");
                    // }
                    // 关闭进度条
                    this.showProgress = false;
                    // 重置进度条
                    this.progress = 0;
                    resolve();
                } catch (e) {
                    reject(e);
                }
            });
        },
        // 文件分块,利用Array.prototype.slice方法
        splitFile(file, eachSize, chunks) {
            return new Promise((resolve, reject) => {
                try {
                    setTimeout(() => {
                        const fileChunk = [];
                        for (let chunk = 0; chunks > 0; chunks--) {
                            fileChunk.push(file.slice(chunk, chunk + eachSize));
                            chunk += eachSize;
                        }
                        resolve(fileChunk);
                    }, 0);
                } catch (e) {
                    console.error(e);
                    reject(new Error("文件切块发生错误"));
                }
            });
        },
        removeFile(file) {
            this.requestCancelQueue[file.uid]();
            delete this.requestCancelQueue[file.uid];
            return true;
        },
        // 提交文件方法,将参数转换为FormData, 然后通过axios发起请求
        postFile(param, onProgress) {
            // console.log(param);
            const formData = new FormData();
            // for (let p in param) {
            // formData.append(p, param[p]);
            // }
            formData.append("file", param.file); //  改了
            formData.append("uid", param.uid);
            formData.append("chunk", param.chunk);
            formData.append("filter_type", "git_secret_file");
            const { requestCancelQueue } = this;
            const config = {
                cancelToken: new axios.CancelToken(function executor(cancel) {
                    if (requestCancelQueue[param.uid]) {
                        requestCancelQueue[param.uid]();
                        delete requestCancelQueue[param.uid];
                    }
                    requestCancelQueue[param.uid] = cancel;
                }),
                onUploadProgress: e => {
                    if (param.chunked) {
                        e.percent = Number(
                            (
                                ((param.chunk * (param.eachSize - 1) + e.loaded) /
                                    param.fullSize) *
                                100
                            ).toFixed(2)
                        );
                    } else {
                        e.percent = Number(((e.loaded / e.total) * 100).toFixed(2));
                    }
                    onProgress(e);
                }
            };
            // return axios.post('/api/v1/tools/upload_chunk/', formData, config).then(rs => rs.data)
            return this.$http({
                url: "/tools/upload_chunk/",
                method: "POST",

                data: formData
                // config
            }).then(rs => rs.data);
        },
        // 文件校验方法
        validateFile(file) {
            // return axios.post('/api/v1/tools/upload_chunk/', file).then(rs => rs.data)
            return this.$http({
                url: "/tools/upload_chunk/upload_success/",
                method: "POST",
                data: file
            }).then(res => {
                if (res && res.status == 1) {
                    this.againSplitUpload(file, res.data.error_file);
                    this.$message({
                        message: "有文件上传失败，正在重新上传",
                        type: "warning"
                    });
                } else if (res && res.status == 0) {
                    this.$message({
                        message: "上传成功",
                        type: "success"
                    });
                    this.showProgress = false;
                    this.progress = 0;
                } else if (res && res.status == 40008) {
                    this.$message.error(res.message);
                    this.showProgress = false;
                    this.progress = 0;
                }
            });
        }
    }
};
</script>
<style scoped>
.loading {
    /* 整体页面置灰 */
    /* background: rgba(0, 0, 0, 0.5); */
}

.progress {
    /* 在当前页面居中 */
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    margin-top: 40px;
    /* 宽度 */
}

/deep/ .el-dialog {
    position: relative;
    height: 500px;
}
</style>
